package com.lxx.codegen;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

public class TemplateProcessor {
	private static final Logger LOGGER = LoggerFactory.getLogger(TemplateProcessor.class);
	
	/**
	 * 源代码路径, src/main/java
	 */
	private String rootPath;
	/**
	 * webapp路径,如 src/main/webapp
	 */
	private String webappPath;
	private Configuration conf;
	/**
	 * 该模型对应的java类名
	 */
	private String modelName;
	/**
	 * 用来渲染的数据模型
	 */
	private Map<String, Object> dataModel;
	
	public TemplateProcessor() {
		super();
	}
	public TemplateProcessor(String rootPath, Configuration conf, String modelName, Map<String, Object> dataModel) {
		super();
		this.rootPath = rootPath;
		this.conf = conf;
		this.modelName = modelName;
		this.dataModel = dataModel;
	}
	
	public TemplateProcessor(String rootPath, String webappPath, Configuration conf, String modelName, Map<String, Object> dataModel) {
		super();
		this.rootPath = rootPath;
		this.webappPath = webappPath;
		this.conf = conf;
		this.modelName = modelName;
		this.dataModel = dataModel;
	}
	
	/**
	 * 渲染模板,生成java文件
	 * 最终会在 packageName包 下 生成模板
	 * @param packageName 包名,  如a.b.c
	 * @param tmplName 模板名称
	 * @throws TemplateNotFoundException
	 * @throws MalformedTemplateNameException
	 * @throws ParseException
	 * @throws IOException
	 * @throws TemplateException
	 */
	public void processTemplate(String packageName, String tmplName) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
		processTemplate(packageName, tmplName, false, true);
	}
	
	/**
	 * 渲染模板,生成文件
	 * 最终会在 packageName包 下 生成模板
	 * @param packageName 包名,  可以是包名a.b.c, 也可以是常规的文件路径 a/b/c
	 * @param tmplName 模板名称,即模板路径
	 * @param isWebPage 是否是web页面
	 * @param useTmplPath 是否要按照模板的路径去生成最终文件的路径,  例如 模板为 a/b.ftl, 如果该选项是true,则最终生成的文件路径也是在a下面
	 * @throws TemplateNotFoundException
	 * @throws MalformedTemplateNameException
	 * @throws ParseException
	 * @throws IOException
	 * @throws TemplateException
	 */
	public void processTemplate(String packageName, String tmplName, boolean isWebPage, boolean useTmplPath) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
		Configuration cfg = this.conf;
		String prjPath = rootPath;
		String modelName = this.modelName;
		Template template = cfg.getTemplate(tmplName);
		
		if (!useTmplPath) {
			// 提取出模板路径的文件名,不要上层文件夹   例如从  a/b/c中提取c
			tmplName = tmplName.replace("/", File.separator);
			tmplName = tmplName.substring(tmplName.lastIndexOf(File.separator)+1);
		}
		
		// 找到模板最终生成的路径
		String outputPath;
		if (isWebPage) {
			// web页面,名称首字母小写, 和modelVarName相同
			outputPath = GeneratorUtils.getGenerateFilePath(this.webappPath, packageName, tmplName, StringUtils.uncapitalize(modelName));
		} else {
			outputPath = GeneratorUtils.getGenerateFilePath(prjPath, packageName, tmplName, modelName);
		}
		
		File f = new File(outputPath);
		if (!f.getParentFile().exists()) {
			LOGGER.info("make dirs:{}", f.getParentFile());
			f.getParentFile().mkdirs();
		}
		try (Writer out = new OutputStreamWriter(new FileOutputStream(outputPath))) {
			template.process(dataModel, out);
		}
	}

	
	public String getRootPath() {
		return rootPath;
	}
	public void setRootPath(String rootPath) {
		this.rootPath = rootPath;
	}
	public Configuration getConf() {
		return conf;
	}
	public void setConf(Configuration conf) {
		this.conf = conf;
	}
	public String getModelName() {
		return modelName;
	}
	public void setModelName(String modelName) {
		this.modelName = modelName;
	}
	public Map<String, Object> getDataModel() {
		return dataModel;
	}
	public void setDataModel(Map<String, Object> dataModel) {
		this.dataModel = dataModel;
	}

}
